﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NAudio.Wave;
using System.Security;
using System.Security.Cryptography;
using System.IO;
using System.IO.Compression;
using NAudio.Codecs;
using NSpeex;

namespace slCommunicator
{
    public static class AudioPrepare
    {
        private static bool bEncode = Properties.Settings.Default.doEncoding;
        private static bool bCrypto = Properties.Settings.Default.doCrypto;

        private static byte[] Key;
        private static RijndaelManaged AES;
        private static readonly byte[] mySalt = new byte[] { 146, 64, 191, 111, 23, 3, 113, 119 };

        public static WaveFormat wformat = DuplexAudio.wformat;

        private static NAudioDemo.NetworkChatDemo.SpeexChatCodec scc =
            new NAudioDemo.NetworkChatDemo.SpeexChatCodec(BandMode.Narrow, wformat, Properties.Settings.Default.audio_speexQuality);

        public static void CreateCrypto()
        {
            Key = ContactInformation.MyContactInfo.PasswordMd5Byte;

            AES = new RijndaelManaged();
            var key = new Rfc2898DeriveBytes(Key, mySalt, 1000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);

            AES.Mode = CipherMode.CBC;

            Console.WriteLine(localization.session_cryptoApparatusCreated);
        }

        private static byte[] CTransform(byte[] input, bool mode)
        {
            if (!bCrypto)
                return input;

            MemoryStream ms = new MemoryStream();
            var transformer = mode ? AES.CreateEncryptor() : AES.CreateDecryptor();
            using (var cs = new CryptoStream(ms, transformer, CryptoStreamMode.Write))
            {
                cs.Write(input, 0, input.Length);
                cs.Close();
            }
            return ms.ToArray();
        }

        private static byte[] Encrypt(byte[] clearBytes)
        {
            return CTransform(clearBytes, true);
        }

        private static byte[] Decrypt(byte[] cipherBytes)
        {
            return CTransform(cipherBytes, false);
        }

        public static byte[] EncodeSpeex(byte[] input)
        {
            return scc.Encode(input, 0, input.Length);
        }

        public static byte[] DecodeSpeex(byte[] input)
        {
            return scc.Decode(input, 0, input.Length);
        }

        public static byte[] PrepareToSend(byte[] data)
        {
            byte[] encodedData;
            if (bEncode)
                encodedData = EncodeSpeex(data);
            else
                encodedData = data;

            byte[] encryptedData;
            if (bCrypto)
                encryptedData = Encrypt(encodedData);
            else
                encryptedData = encodedData;

            return encryptedData;
        }
        public static byte[] PrepareReceived(byte[] data)
        {
            byte[] decryptedData;
            if (bCrypto)
                decryptedData = Decrypt(data);
            else
                decryptedData = data;

            byte[] decodedData;
            if (bEncode)
                decodedData = DecodeSpeex(decryptedData);
            else
                decodedData = decryptedData;

            return decodedData;
        }
    }
}
